#include "ipaddr.h"
#include <qsciscintilla.h>

typedef void (*line_func_t)(const QString & line, QString & buf);
QMessageBox * debug;
#define DEBUG(str) if(debug) {debug->setText(str); debug->exec();}

IpAddrPlugin::IpAddrPlugin(QWidget *parent, QsciScintilla* pEdit)
	: QWidget(parent)
{
	ui.setupUi(this);
	m_pEdit = pEdit;
}

IpAddrPlugin::~IpAddrPlugin()
{}

bool IPV4_BYTE(int i, const QStringList & splitted, uint32_t & net){
    bool ok;
    DEBUG("IPV4_BYTE");
    int b = splitted.at(i).toInt(&ok);
    if(!ok || (b < 0) || (b > 0xff)) return false;
        net = net | (b << (3-i) * 8);
    return true;
}
//little endian
bool parse_ipv4_network(const QString & network, uint32_t & net, uint32_t & mask){
    DEBUG("parse_ipv4_network")
    DEBUG(network)
    int j = network.indexOf('/');
    if(j <= 0 || j >= network.size()-1) return false;
    QString net_s = network.left(j);
    DEBUG(net_s)
    QStringList splitted = net_s.split('.');
    if(splitted.size() != 4) return false;
    net = 0;
    if(!IPV4_BYTE(0, splitted, net)) return false;
    if(!IPV4_BYTE(1, splitted, net)) return false;
    if(!IPV4_BYTE(2, splitted, net)) return false;
    if(!IPV4_BYTE(3, splitted, net)) return false;
    QString prefix_s = network.right(network.size() - j-1);
    bool ok;
    int b;
    b = prefix_s.toInt(&ok);
    if(!ok || (b < 0) || (b > 32)) return false;
    mask = 0xffffffff << (32 - b);
    net = net & mask;
    return true;
}
inline void appendIpv4Addr(QString & s, uint32_t addr){
    s.append(QString("%1.%2.%3.%4").arg(addr >> 24).arg((addr & 0x00ff0000) >> 16).arg((addr & 0x0000ff00) >> 8).arg((addr & 0x000000ff)));
}
//subnet 10.2.101.0 netmask 255.255.255.0 {
//#BGL Wan 1
//range 10.2.101.10 10.2.101.200;
//option broadcast-address 10.2.101.255;
//option subnet-mask 255.255.255.0;
//option routers 10.2.101.254;
//}
void dhcp_func(const QString & line, QString & buf){
    uint32_t net, mask;
    DEBUG("dhcp_func")
    if(!parse_ipv4_network(line, net, mask)){
        DEBUG("parse fail")
        buf.append(line);
    }else{
        DEBUG("parse ok")
        buf.append("subnet ");
        appendIpv4Addr(buf, net);
        buf.append(" netmask ");
        appendIpv4Addr(buf, mask);
        buf.append(" {\r\n\trange ");
        appendIpv4Addr(buf, net + 10);
        buf.append(' ');
        appendIpv4Addr(buf, (net | ~mask) - 10);
        buf.append(";\r\n\toption broadcast-address ");
        appendIpv4Addr(buf, net | ~mask);
        buf.append(";\r\n\toption subnet-mask ");
        appendIpv4Addr(buf, mask);
        buf.append(";\r\n\toption routers ");
        appendIpv4Addr(buf, (net | ~mask) - 1);
        buf.append(";\r\n}\r\n");
    }
    buf.append("\r\n");
}

//int vl 1
//ip addr 1.1.1.254 255.255.255.0
//exit
void vlan_func(const QString & line, QString & buf){
    int j = line.indexOf('\t');
    if(j <= 0 || j >= line.size()-1)
        buf.append(line);
    else{
        QString vlan_s = line.left(j);
        bool ok;
        int vlan_id = vlan_s.toInt(&ok);
        if(!ok || vlan_id <= 0 || vlan_id > 4094)
            buf.append(line);
        else{
            uint32_t net, mask;
            if(!parse_ipv4_network(line.right(line.size()-j-1), net, mask))
                buf.append(line);
            else{
                buf.insert(0, "\r\n");
                buf.insert(0, vlan_s);
                buf.insert(0, "vlan ");
                buf.append("interface vlan ");
                buf.append(vlan_s);
                buf.append("\r\nip address ");
                appendIpv4Addr(buf, (net | ~mask) - 1);
                buf.append(' ');
                appendIpv4Addr(buf, mask);
                buf.append("\r\nexit\r\n");
            }
        }
    }
    buf.append("\r\n");
}
void IpAddrPlugin::on_execBtn_clicked()
{
    //debug = &msg;
    debug = NULL;
    QString old = m_pEdit->text();
    QStringList splitted = old.split("\r\n", Qt::SkipEmptyParts);
    QString buf = "";
    line_func_t func;
    if(ui.dhcpRadio->isChecked())
        func = dhcp_func;
    else
        func = vlan_func;
    DEBUG(buf)
    for(int i=0; i<=splitted.size()-1; i++)
        func(splitted.at(i), buf);
    m_pEdit->setText(buf);
}

